#!/usr/bin/env python
######################################################################
##
## Copyright (C) 2006,  Blekinge Institute of Technology
##
## Filename:      mips2java
## Author:        Simon Kagstrom <ska@bth.se>
## Description:   MIPS binary -> Java bytecode compiler.
##
## $Id: cibyl-mips2java 14249 2007-03-14 17:14:05Z ska $
##
######################################################################
import sys, os, struct, re
from optparse import OptionParser

sys.path.append('%s/python/' % sys.path[0])

from Cibyl.BinaryTranslation.translator import Controller
from Cibyl.BinaryTranslation.translator import config

# Handling of the -I option is done through this callback
syscallDirectories = []
def includeCallback(option, opt, value, parser):
    syscallDirectories.append(value)

usage = """usage: %prog [options] infile

Recompile the big-endian MIPS ELF file 'infile' to Java bytecode
assembly. The 'dir' directories are the directories with the C headers
generated by cibyl-generate-c-headers.
"""
parser = OptionParser(usage = usage)
parser.add_option("-t", "--trace-instructions", action="store_true", dest="tracing", default=False,
                  help="generate an instruction trace for all functions")
parser.add_option("--trace-function-calls", action="store_true", dest="traceFunctionCalls", default=False,
                  help="generate a trace of function calls")
parser.add_option("--trace-function-instructions", dest="traceFunctions", default=None,
                  help="generate an instruction trace for the FUNCTIONS (comma-separated)",
		  metavar="FUNCTIONS")
parser.add_option("-d", "--data-filename",
                  help="write the data outfile to outfile instead of program.data.bin",
		  dest="dataOutfile", metavar="FILE", default="program.data.bin")
parser.add_option("-I", "--include", action="callback", help="directory to search for header files",
		  type="str", nargs=1,
		  callback=includeCallback)
parser.add_option("-o", "--out-filename",
                  help="write the assembly output to outfile instead of stdout",
		  dest="outfile", metavar="FILE")
parser.add_option("-g", "--debug", action="store_true", default=False,
		  help="""Turn on generation of debugging information.""",
		  dest="debug")
parser.add_option("--optimize-memory-registers", action="store_true", default=False,
		  help="""Turn on the memory register optimization. This improves performance of
frequent accesses to the same register in a basic block.""",
		  dest="memory_register_optimization")
parser.add_option("--optimize-multiplications", action="store_true", default=False,
                  help="""Turn on the mult/div optimizations. This improves the performance of
most multiplications and divisions.""",
		  dest="multiplication_optimization")
parser.add_option("--optimize-register-scheduling", action="store_true", default=False,
                  help="""Perform register scheduling to reduce the number of registers used by
a function. The number of arguments passed to leaf functions can also
be reduced. This reduces the size of the executable and can provide
performance advantages for frequently called short functions.""",
		  dest="optimize_register_scheduling")
parser.add_option("-O", "--optimize-all", action="store_true", default=False,
                  help="""Enable all optimizations above and unused function pruning.""",
		  dest="optimize_all")
parser.add_option("-v", "--verbose", action="store_true", dest="verbose", default=False,
                  help="be verbose")

(options, args) = parser.parse_args()
if len(args) != 1:
    parser.error("incorrect number of arguments. Invoke with --help for arguments")
infile = args[0]

config.doMultOptimization = options.multiplication_optimization
config.doMemoryRegisterOptimization = options.memory_register_optimization
config.doRegisterScheduling = options.optimize_register_scheduling

config.debug = options.debug
config.tracing = options.tracing
config.traceFunctionCalls = options.traceFunctionCalls
config.verbose = options.verbose
config.outFilename = options.outfile

if options.traceFunctions:
    config.traceFunctions = options.traceFunctions.split(",")

if options.optimize_all:
    config.doMultOptimization = True
    config.doMemoryRegisterOptimization = True
    config.doRegisterScheduling = True

# Read it all
controller = Controller(infile, syscallDirectories)

controller.compile()
controller.writeAssemblyFile(options.outfile)
controller.writeDataFile(options.dataOutfile)
